//: Playground - noun: a place where people can play

import UIKit

/*
 1.系统要求存储属性必须初始化
 2.可选值可以不用初始化,如果不初始化值,系统默认用nil初始化它
 3.如果非可选类型存储属性不设置默认值,则必须在初始化方法中对其进行初始化
 4.类必须自己写初始化方法,初始化没有默认值的非可选存储属性
 5.结构体系统默认会添加初始化方法,当然自己也可以自定义
 6.子类如果没有自己的初始化方法,系统默认使用父类的初始化方法,一旦有了自己的初始化方法,或者重写了父类的初始化方法,则父类的所有初始化不能被子类调用
 7.你可以给子类添加和父类相同的初始化方法,但需要加上override 修饰
 8.重写父类的convenience修饰的方便初始化方法,不需要加override 关键字
 */

// 可以有多个指定初始化方法
class Person {
    
    var name: String
    var age:Int = 0
    var weight:Double = 0.0
    var height:Double = 0.0
    
    init(name: String, height: Double) {
        
        self.name = name
        self.height = height;
    }
    
    init(name: String) {
        
        self.name = name
    }
}

var xiaoming = Person(name: "小明")
var xiaoli = Person(name: "xiaoming", height: 66.0)

// 方便初始化（convenience）
/*
 1.在同一个类,使用convenience修饰的初始化方法必须调用一个其他初始化方法
 2.convenience 必须最终调用一个指定的初始化方法
 3.当子类继承父类时,子类的初始化方法,必须调用父类的指定初始化方法,不能调用使用convienience修饰的方便初始化方法
 4.在swift3.0 初始化中,可以自己调用自己的初始化方法,系统不会检测出来,在创建convenience方便初始化方法的时候,需要小心,千万不要相互引用了
 */

// 父类
class Person2{
    var name:String
    var age:Int = 0
    var weight:Double = 0.0
    var height:Double = 0.0
    init(name:String,height:Double) {
        self.name = name
        self.height = height
    }
    init(name:String) {
        self.name = name
    }
    convenience init(name:String,age:Int,weight:Double){
        self.init(name:name)
        self.age = age
        self.weight = weight
    }
}
// 子类
class Man2: Person2 {
    var address:String = ""
    
    // 重写父类指定初始化方法
    override init(name:String) {
        super.init(name: name)
    }
    // 重写父类convenience 修饰的初始化方法 不需要添加override 关键字
    init(name:String,age:Int,weight:Double){
        super.init(name: name)
    }
    // 创建自己的初始化方法
    convenience init(name:String,age:Int,weight:Double,address:String){
        self.init(name: name)
        self.address = address
        self.age = age
        self.weight = weight
    }
}

/*
 1.创建新的指定初始化方法,必须调用父类的指定初始化方法 (Designated)
 2.创建新的方便初始化方法,必须调用自己的指定初始化方法,或者方便初始化方法(convenience)
 3.重写父类的指定初始化方法,在方法名前加override ,然后调用父类的指定初始化方法
 4.重写父类的方便初始化方法(convenience) 不需要加override 或者convenience 关键字,调用父类的指定初始化方法,如果加上convenice关键字,则必须调用自己的初始化方法
 5.如果子类没有初始化方法,系统会自动继承父类的初始化方法
 6.初始化调用父类初始化时,需要先初始化子类的存储属性,但是如果是convenience修饰的初始化方法,要先调用自己的其他初始化方法,然后再给自己的存储属性赋值
 */


// 需要的初始化方法（required）

/*
 1.子类必须重写父类用required修饰的方法
 2.可以和convenience 组合使用
 */

// a-1 父类要求一个初始化方法 被重写
class Person5{
    var name:String
    var age:Int = 0
    var weight:Double = 0.0
    var height:Double = 0.0
    init(name:String,height:Double) {
        self.name = name
        self.height = height
    }
    init(name:String) {
        self.name = name
    }
    // 要求子类必须重写这个方法
    required convenience init(name:String,age:Int,weight:Double){
        self.init(name:name)
        self.age = age
        self.weight = weight
    }
}

// a-2 子类重写父类要求的初始化方法
class Man5: Person5 {
    
    var address:String = ""
    
    // 重写父类要求的初始化convenience 修饰的初始化方法 不需要添加override 关键字
    required init(name:String,age:Int,weight:Double) {
        
        super.init(name: name);
    }
}

var man5 = Person5(name: "888")

print(man5.name)


// 反初始化 deinit 在对象被释放前调用

class Bank {
    static var coinsInBank = 10_000
    static func distribute(coins numberOfCoinsRequested: Int) -> Int {
        let numberOfCoinsToVend = min(numberOfCoinsRequested, coinsInBank)
        coinsInBank -= numberOfCoinsToVend
        return numberOfCoinsToVend
    }
    static func receive(coins: Int) {
        coinsInBank += coins
    }
}

class Player {
    var coinsInPurse: Int
    init(coins: Int) {
        coinsInPurse = Bank.distribute(coins: coins)
    }
    func win(coins: Int) {
        coinsInPurse += Bank.distribute(coins: coins)
    }
    // 反初始化
    deinit {
        Bank.receive(coins: coinsInPurse)
        print("进入反初始化了")
    }
}

var playerOne: Player? = Player(coins: 100)
playerOne!.win(coins: 2_000)
playerOne = nil



